feat: add HTTP subscription support via polling#32
feat: add HTTP subscription support via polling#320xNeshi merged 39 commits intoOpenZeppelin:mainfrom
Conversation
Implements OpenZeppelin#23 - Support HTTP Subscription This PR adds the ability for HTTP providers to participate in block subscriptions via polling, enabling use cases where WebSocket connections are not available (e.g., behind load balancers). ## Changes ### New Feature (behind `http-subscription` feature flag) - Add `HttpPollingSubscription` that polls `eth_getBlockByNumber(latest)` at configurable intervals - Add `SubscriptionBackend` enum to handle both WebSocket and HTTP backends - Add `poll_interval()` and `allow_http_subscriptions()` builder methods - Seamless failover between mixed WS/HTTP provider chains ### Files - `src/robust_provider/http_subscription.rs` - New HTTP polling module - `src/robust_provider/subscription.rs` - Unified backend handling - `src/robust_provider/builder.rs` - New configuration options - `src/robust_provider/provider.rs` - Updated subscribe_blocks() - `Cargo.toml` - Added `http-subscription` feature flag ## Usage ```rust let robust = RobustProviderBuilder::new(http_provider) .allow_http_subscriptions(true) .poll_interval(Duration::from_secs(12)) .build() .await?; let mut sub = robust.subscribe_blocks().await?; ``` ## Trade-offs (documented) - Latency: up to `poll_interval` delay for block detection - RPC Load: one call per `poll_interval` - Feature-gated to ensure explicit opt-in Closes OpenZeppelin#23
64ba47c to
3a73de3
Compare
Add comprehensive integration tests in tests/http_subscription.rs: - test_http_subscription_basic_flow - test_http_subscription_multiple_blocks - test_http_subscription_as_stream - test_failover_from_ws_to_http - test_failover_from_http_to_ws - test_mixed_provider_chain_failover - test_http_reconnects_to_ws_primary - test_http_only_no_ws_providers - test_http_subscription_disabled_falls_back_to_ws - test_custom_poll_interval All tests gated behind #[cfg(feature = "http-subscription")]
Audit findings addressed: Unit tests (http_subscription.rs): - Improved test_http_polling_deduplication with better verification - Renamed test_http_polling_handles_drop → test_http_polling_stops_on_drop with clearer verification logic - Added test_http_subscription_error_types for all error variants - Added test_http_polling_close_method for close() functionality Integration tests (tests/http_subscription.rs) - rewritten: - Removed broken test_http_reconnects_to_ws_primary (was meaningless) - Removed flawed test_custom_poll_interval, replaced with test_poll_interval_is_respected (measures correctly) - Renamed tests for clarity on what they actually verify - Added test_http_disabled_no_ws_fails (negative test case) - Added test_all_providers_fail_returns_error (error handling) - Added test_http_subscription_survives_temporary_errors - Added test_http_polling_deduplication (integration level) - Fixed failover tests to verify behavior correctly - Removed fragile 'pre-mine to distinguish providers' hacks Test count: 73 total (19 unit + 12 http integration + 24 subscription + 18 eth)
Tests verify that RPC calls (not just subscriptions) properly: - Failover to fallback providers when primary dies - Cycle through multiple fallbacks - Return errors when all providers exhausted - Don't retry non-retryable errors (BlockNotFound) - Complete within bounded time when providers unavailable - Work correctly for various RPC methods (get_accounts, get_balance, get_block)
Fixes two bugs in HTTP subscription handling: 1. http_config now uses configured values from RobustProviderBuilder instead of defaults when a WebSocket subscription is created first. This ensures poll_interval, call_timeout, and buffer_capacity are respected when failing over to HTTP. 2. HTTP reconnection now validates the provider is reachable before claiming success. Uses a short 50ms timeout to quickly fail and not block the failover process. Also fixes test timing in test_failover_http_to_ws_on_provider_death to mine before subscription timeout instead of after. Adds two new tests: - test_poll_interval_propagated_from_builder: verifies config propagation - test_http_reconnect_validates_provider: verifies reconnect validation
f94c84d to
b6001af
Compare
Implements OpenZeppelin#23 - Support HTTP Subscription This PR adds the ability for HTTP providers to participate in block subscriptions via polling, enabling use cases where WebSocket connections are not available (e.g., behind load balancers). - Add `HttpPollingSubscription` that polls `eth_getBlockByNumber(latest)` at configurable intervals - Add `SubscriptionBackend` enum to handle both WebSocket and HTTP backends - Add `poll_interval()` and `allow_http_subscriptions()` builder methods - Seamless failover between mixed WS/HTTP provider chains - `src/robust_provider/http_subscription.rs` - New HTTP polling module - `src/robust_provider/subscription.rs` - Unified backend handling - `src/robust_provider/builder.rs` - New configuration options - `src/robust_provider/provider.rs` - Updated subscribe_blocks() - `Cargo.toml` - Added `http-subscription` feature flag ```rust let robust = RobustProviderBuilder::new(http_provider) .allow_http_subscriptions(true) .poll_interval(Duration::from_secs(12)) .build() .await?; let mut sub = robust.subscribe_blocks().await?; ``` - Latency: up to `poll_interval` delay for block detection - RPC Load: one call per `poll_interval` - Feature-gated to ensure explicit opt-in Closes OpenZeppelin#23
Add comprehensive integration tests in tests/http_subscription.rs: - test_http_subscription_basic_flow - test_http_subscription_multiple_blocks - test_http_subscription_as_stream - test_failover_from_ws_to_http - test_failover_from_http_to_ws - test_mixed_provider_chain_failover - test_http_reconnects_to_ws_primary - test_http_only_no_ws_providers - test_http_subscription_disabled_falls_back_to_ws - test_custom_poll_interval All tests gated behind #[cfg(feature = "http-subscription")]
Audit findings addressed: Unit tests (http_subscription.rs): - Improved test_http_polling_deduplication with better verification - Renamed test_http_polling_handles_drop → test_http_polling_stops_on_drop with clearer verification logic - Added test_http_subscription_error_types for all error variants - Added test_http_polling_close_method for close() functionality Integration tests (tests/http_subscription.rs) - rewritten: - Removed broken test_http_reconnects_to_ws_primary (was meaningless) - Removed flawed test_custom_poll_interval, replaced with test_poll_interval_is_respected (measures correctly) - Renamed tests for clarity on what they actually verify - Added test_http_disabled_no_ws_fails (negative test case) - Added test_all_providers_fail_returns_error (error handling) - Added test_http_subscription_survives_temporary_errors - Added test_http_polling_deduplication (integration level) - Fixed failover tests to verify behavior correctly - Removed fragile 'pre-mine to distinguish providers' hacks Test count: 73 total (19 unit + 12 http integration + 24 subscription + 18 eth)
Tests verify that RPC calls (not just subscriptions) properly: - Failover to fallback providers when primary dies - Cycle through multiple fallbacks - Return errors when all providers exhausted - Don't retry non-retryable errors (BlockNotFound) - Complete within bounded time when providers unavailable - Work correctly for various RPC methods (get_accounts, get_balance, get_block)
Fixes two bugs in HTTP subscription handling: 1. http_config now uses configured values from RobustProviderBuilder instead of defaults when a WebSocket subscription is created first. This ensures poll_interval, call_timeout, and buffer_capacity are respected when failing over to HTTP. 2. HTTP reconnection now validates the provider is reachable before claiming success. Uses a short 50ms timeout to quickly fail and not block the failover process. Also fixes test timing in test_failover_http_to_ws_on_provider_death to mine before subscription timeout instead of after. Adds two new tests: - test_poll_interval_propagated_from_builder: verifies config propagation - test_http_reconnect_validates_provider: verifies reconnect validation
e4d249d to
06a94ff
Compare
0xNeshi
left a comment
There was a problem hiding this comment.
Thanks for the contribution!
First "shallower" review iteration, will dive deeper in the following ones
|
Also, resolve conflicts please |
- Add http-subscription feature to VSCode settings for rust-analyzer - Make HTTP_RECONNECT_VALIDATION_TIMEOUT public - Fix HTTP subscription fallback: try fallback providers when primary HTTP fails - Fix buffer_capacity: use mpsc channel with configured capacity - Fix error documentation: use proper error list with stars - Remove unused imports (FutureExt, Stream)
- Add pub const DEFAULT_CALL_TIMEOUT (30 seconds) - Add pub const DEFAULT_BUFFER_CAPACITY (128) - Update rustdocs to reference the new constants - Update Default impl to use constants instead of magic numbers - Update test to use constants for consistency Addresses reviewer comment on line 105 about converting constants into actual pub const values.
0xNeshi
left a comment
There was a problem hiding this comment.
After all there are still some things to address
|
@0xNeshi are there any further tests to be written post your PR? |
|
The failing test is flaky, will be handled as part of #59 |
|
@smartprogrammer93 we'd like to get this merged for you asap, I will create a new PR addressing all of the comments. Merge that, and we merge this. |
Should I address the comments you made or are you making a new PR to this? |
I'm making it, will have it up in the next 10-15 mins |
0xNeshi
left a comment
There was a problem hiding this comment.
Glad we were able to finalize this, thanks for the good work (and patience) @smartprogrammer93
Summary
Implements HTTP subscription support via polling, allowing HTTP providers to participate in block subscriptions alongside WebSocket providers.
Resolves #23
Features
watch_blocks()API witheth_newBlockFilter+eth_getFilterChangesfor efficient block pollingRobustSubscriptionAPI - callers use the samesubscribe_blocks()andrecv()interfaceUsage
Enable the
http-subscriptionfeature flag:Build with HTTP subscription support:
Breaking Changes
None. Feature is behind
http-subscriptionflag and disabled by default.Thanks to @PoulavBhowmick03 for the massive improvements to this implementation.
Closes #23